
<!DOCTYPE HTML>
<html lang="zh-hans" >
    <head>
        <meta charset="UTF-8">
        <title>10 输入输出 · C++导览 第二版 简体中文版</title>
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="description" content="">
        <meta name="generator" content="HonKit 5.1.1">
        <meta name="author" content="Windsting">
        
        
    
    <link rel="stylesheet" href="gitbook/style.css">

    
            
                
                <link rel="stylesheet" href="gitbook/@dogatana/honkit-plugin-page-toc-button/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/@dogatana/honkit-plugin-back-to-top-button/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-forkmegithub/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/@honkit/honkit-plugin-highlight/website.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-search/search.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-fontsettings/website.css">
                
            
        

    

    
        
        <link rel="stylesheet" href="styles/website.css">
        
    
        
    
        
    
        
    
        
    
        
    

        
    
    
    <meta name="HandheldFriendly" content="true"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="apple-touch-icon-precomposed" sizes="152x152" href="gitbook/images/apple-touch-icon-precomposed-152.png">
    <link rel="shortcut icon" href="gitbook/images/favicon.ico" type="image/x-icon">

    
    <link rel="next" href="ch11.html" />
    
    
    <link rel="prev" href="ch09.html" />
    

    </head>
    <body>
        
<div class="book honkit-cloak">
    <div class="book-summary">
        
            
<div id="book-search-input" role="search">
    <input type="text" placeholder="输入并搜索" />
</div>

            
                <nav role="navigation">
                


<ul class="summary">
    
    
    
        
        <li>
            <a href="https://github.com/windsting/a-tour-of-cpp-2nd-cn" target="_blank" class="custom-link">Github Link</a>
        </li>
    
    

    
    <li class="divider"></li>
    

    
        
        
    
        <li class="chapter " data-level="1.1" data-path="translation_note.html">
            
                <a href="translation_note.html">
            
                    
                    译者言
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.2" data-path="./">
            
                <a href="./">
            
                    
                    前言
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.3" data-path="ch01.html">
            
                <a href="ch01.html">
            
                    
                    1 基础知识
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.4" data-path="ch02.html">
            
                <a href="ch02.html">
            
                    
                    2 用户定义类型
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.5" data-path="ch03.html">
            
                <a href="ch03.html">
            
                    
                    3 模块化
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.6" data-path="ch04.html">
            
                <a href="ch04.html">
            
                    
                    4 类
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.7" data-path="ch05.html">
            
                <a href="ch05.html">
            
                    
                    5 基本操作
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.8" data-path="ch06.html">
            
                <a href="ch06.html">
            
                    
                    6 模板
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.9" data-path="ch07.html">
            
                <a href="ch07.html">
            
                    
                    7 概束和泛型编程
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.10" data-path="ch08.html">
            
                <a href="ch08.html">
            
                    
                    8 标准库概览
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.11" data-path="ch09.html">
            
                <a href="ch09.html">
            
                    
                    9 字符串和正则表达式
            
                </a>
            

            
        </li>
    
        <li class="chapter active" data-level="1.12" data-path="ch10.html">
            
                <a href="ch10.html">
            
                    
                    10 输入输出
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.13" data-path="ch11.html">
            
                <a href="ch11.html">
            
                    
                    11 容器
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.14" data-path="ch12.html">
            
                <a href="ch12.html">
            
                    
                    12 算法
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.15" data-path="ch13.html">
            
                <a href="ch13.html">
            
                    
                    13 实用功能
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.16" data-path="ch14.html">
            
                <a href="ch14.html">
            
                    
                    14 数值
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.17" data-path="ch15.html">
            
                <a href="ch15.html">
            
                    
                    15 并发
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.18" data-path="ch16.html">
            
                <a href="ch16.html">
            
                    
                    16 历史及兼容性
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.19" data-path="idx.html">
            
                <a href="idx.html">
            
                    
                    索引
            
                </a>
            

            
        </li>
    

    

    <li class="divider"></li>

    <li>
        <a href="https://github.com/honkit/honkit" target="blank" class="gitbook-link">
            本书使用 HonKit 发布
        </a>
    </li>
</ul>


                </nav>
            
        
    </div>

    <div class="book-body">
        
            <div class="body-inner">
                
                    

<div class="book-header" role="navigation">
    

    <!-- Title -->
    <h1>
        <i class="fa fa-circle-o-notch fa-spin"></i>
        <a href="." >10 输入输出</a>
    </h1>
</div>




                    <div class="page-wrapper" tabindex="-1" role="main">
                        <div class="page-inner">
                            
<div id="book-search-results">
    <div class="search-noresults">
    
                                <section class="normal markdown-section">
                                

    
        
                                <p><a class="en-page-number" id="123"></a></p>
<div class="chapter-number"><p class="chapter-number">10</p></div>

<h1 id="input-and-output">输入和输出 </h1>
<blockquote>
<p>不见即不得。</p>
<p><span title="这句话的原文是“What you see is all you get.”，没找到出处，可见于他的维基百科页面 https://en.wikipedia.org/wiki/Brian_Kernighan ，未见官方翻译，有一个译法是 [所见即全部所得](https://www.ituring.com.cn/article/17869)，但我理解这里强调的是“某些内容被抛弃”，故按此翻译。" 。>—— Brian W. Kernighan</span><sup><a href="#fn_1" id="reffn_1">1</a></sup></p>
</blockquote>
<h2 id="10.1">10.1 导言 </h2>
<p>I/O流程序库为文本和数字值提供带缓冲输入输出，无论这些值是格式化还是未格式化的。</p>
<p><code>ostream</code>将带有类型的对象转化成字符（字节）流：</p>
<p><img src="img/ch10_01.png" alt="ostream"></p>
<p><a class="en-page-number" id="124"></a></p>
<p><code>istream</code>将字符（字节）流转化成带有类型的对象：</p>
<p><img src="img/ch10_02.png" alt="istream"></p>
<p>这些有关<code>istream</code>和<code>ostrean</code>的操作在 §10.2 和 §10.3 叙述。
这些操作是类型安全、大小写敏感的，并且可扩展以便处理用户定义的那些类型（§10.5）。</p>
<p>其它形式的用户交互，例如图形I/O，可利用程序库处理，但它们并非ISO标准的组成部分，
因此在这里不加赘述。</p>
<p>这些流可用于二进制的 I/O，用于多种字符类型，可进行本地化，还可以采用高级缓冲策略，
但这些主题不在本书的讨论范畴之内。</p>
<p>这些流可用于输入进或输出自<code>string</code>（§10.3），可格式化进<code>string</code>缓冲（§10.8），
还可以处理文件 I/O（§10.10）。</p>
<p>I/O 流相关的类全都具有析构函数，
这些函数会释放所拥有的全部资源（比如缓冲以及文件执柄）。
也就是说，它们是“资源请求即初始化”（RAII；§5.3）的示例。</p>
<h2 id="10.2">10.2 输出 </h2>
<p>I/O流库在<code>&lt;ostream&gt;</code>中为所有内建类型定义了输出。
此外，为用户定义类型定义输出也不难（§10.5）。
操作符<code>&lt;&lt;</code>（“输出到”）是指向<code>ostream</code>类型对象的输出操作符。
默认情况下，写到<code>cout</code>的那些值会被转化成一个字符流。
例如，要输出十进制数字<code>10</code>，可以这样写：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">()</span>
</span>{
    cout &lt;&lt; <span class="hljs-number">10</span>;
}
</code></pre>
<p>这将把字符<code>1</code>后跟着个字符<code>0</code>放置到标准输出流中。</p>
<p>还可以写成这样的等价形式：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">g</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-type">int</span> x{<span class="hljs-number">10</span>};
    cout &lt;&lt; x;
}
</code></pre>
<p>不同的类型在输出时可以清晰直观的方式组合：</p>
<p><a class="en-page-number" id="125"></a></p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">h</span><span class="hljs-params">(<span class="hljs-type">int</span> i)</span>
</span>{
    cout &lt;&lt; <span class="hljs-string">&quot;the value of i is &quot;</span>;
    cout &lt;&lt; i;
    cout &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
}
</code></pre>
<p>对于<code>h(10)</code>，将会输出：</p>
<pre><code class="lang-text">the value of i is 10
</code></pre>
<p>输出多个相关内容的时候，人们很快就会不耐烦去反复敲打输出流的名字。
好在，输出表达式的结果可用于后续输出，例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">h2</span><span class="hljs-params">(<span class="hljs-type">int</span> i)</span>
</span>{
    cout &lt;&lt; <span class="hljs-string">&quot;the value of i is &quot;</span> &lt;&lt; i &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
}
</code></pre>
<p><code>h2()</code>的输出跟<code>h()</code>一样。</p>
<p>字符常量是由单引号包围的字符。请注意，字符会作为字符输出而非一个数值。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">k</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-type">int</span> b = <span class="hljs-string">&apos;b&apos;</span>;    <span class="hljs-comment">// 注意：char 被隐式转换为 int</span>
    <span class="hljs-type">char</span> c = <span class="hljs-string">&apos;c&apos;</span>;
    cout &lt;&lt; <span class="hljs-string">&apos;a&apos;</span> &lt;&lt; b &lt;&lt; c;
}
</code></pre>
<p><code>&apos;b&apos;</code>的整数值是<code>98</code>（在C++实现所采用的ASCII编码中），因此输出是<code>a98c</code>。</p>
<h2 id="10.3">10.3 输入 </h2>
<p>标准库在<code>&lt;istream&gt;</code>中提供了<code>istream</code>用于输入。
与<code>ostream</code>相似，<code>istream</code>也处理以字符串形式表现的内建类型，
也不难处理用户定义类型。</p>
<p>操作符<code>&gt;&gt;</code>（提取自）被用作输入操作符；<code>cin</code>是标准输入流。
<code>&gt;&gt;</code>的右操作数类型决定了可接受的输入内容和输入对象。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-type">int</span> i;
    cin &gt;&gt; i;   <span class="hljs-comment">// 把一个整数读入 i</span>

    <span class="hljs-type">double</span> d;
    cin &gt;&gt; d;   <span class="hljs-comment">// 把一个双精度浮点数读入 d</span>
}
</code></pre>
<p><a class="en-page-number" id="126"></a></p>
<p>以上操作从标准输入读取一个数字，例如<code>1234</code>，进入变量<code>i</code>，
以及一个浮点数，例如<code>12.34e5</code>，进入双精度浮点数变量<code>d</code>。</p>
<p>与输出操作相似，输入操作也可以链式进行，因此可以写作等价的：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-type">int</span> i;
    <span class="hljs-type">double</span> d;
    cin &gt;&gt; i &gt;&gt; d;   <span class="hljs-comment">// 读入 i 和 d</span>
}
</code></pre>
<p>在以上两例中，整数的读取会被任何非数字字符终止。
默认情况下，<code>&gt;&gt;</code>会忽略起始的空白字符，因此一个合适的完整输入可以是：</p>
<pre><code class="lang-text">1234
12.34e5
</code></pre>
<p>通常，我们需要读取一个字符序列。一个便捷的方式是将其读进一个<code>string</code>。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">hello</span><span class="hljs-params">()</span>
</span>{
    cout &lt;&lt; <span class="hljs-string">&quot;Please enter your name\n&quot;</span>;
    string str;
    cin &gt;&gt; str;
    cout &lt;&lt; <span class="hljs-string">&quot;Hello, &quot;</span> &lt;&lt; str &lt;&lt; <span class="hljs-string">&quot;!\n&quot;</span>;
}
</code></pre>
<p>如果你输入<code>Eric</code>，输出将是：</p>
<pre><code class="lang-text">Hello, Eric!
</code></pre>
<p>默认情况下，任意空白字符，例如空格或换行，都会终止输入，
因此，如果你假装自己是命运多舛约克之王而输入<code>Eric Bloodaxe</code>，输出仍会是：</p>
<pre><code class="lang-text">Hello, Eric!
</code></pre>
<p>你可以用<code>getline()</code>函数读取一整行。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">hello_line</span><span class="hljs-params">()</span>
</span>{
    cout &lt;&lt; <span class="hljs-string">&quot;Please enter your name\n&quot;</span>;
    string str;
    <span class="hljs-built_in">getline</span>(cin,str);
    cout &lt;&lt; <span class="hljs-string">&quot;Hello, &quot;</span> &lt;&lt; str &lt;&lt; <span class="hljs-string">&quot;!\n&quot;</span>;
}
</code></pre>
<p>借助这段程序，输入的<code>Eric Bloodaxe</code>就能得到预期的输出：</p>
<pre><code class="lang-text">Hello, Eric Bloodaxe!
</code></pre>
<p>行尾的换行符被丢弃了，因此<code>cin</code>就已经准备好接收下一行输入了。</p>
<p>使用格式化的 I/O 操作通常不易出错，高效，也比一个个字符的操作代码量少。
特别是，<code>istream</code>还会负责内存管理和越界检查。
可以用<code>stringstream</code>针对内存中的内容进行格式化输入和输出（§10.8）。</p>
<p><a class="en-page-number" id="127"></a></p>
<p>标准字符串具有良好的可扩展性，能够保存你放入其中的内容；你无需预计算最大长度。
因此，如果你输入几兆字节的分号，程序就会显示很多页的分号给你。</p>
<h2 id="10.4">10.4 I/O状态 </h2>
<p>一个<code>iostream</code>具有一个状态，可以查询它，以确定某个操作是否成功。
最常见的操作是读取一连串的值：</p>
<pre><code class="lang-cpp"><span class="hljs-function">vector&lt;<span class="hljs-type">int</span>&gt; <span class="hljs-title">read_ints</span><span class="hljs-params">(istream&amp; is)</span>
</span>{
    vector&lt;<span class="hljs-type">int</span>&gt; res;
    <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i; is&gt;&gt;i; )
        res.<span class="hljs-built_in">push_back</span>(i);
    <span class="hljs-keyword">return</span> res;
}
</code></pre>
<p>这段代码从<code>is</code>中读取，直到遇到非数字的内容。该内容通常会成为输入的结束。
此处的情形是<code>is&gt;&gt;i</code>操作返回<code>is</code>的引用，
并检测<code>iostream</code>是否产生了<code>true</code>，并为下一个操作做好准备。</p>
<p>通常，I/O状态持有待读取和写入全部信息，例如格式化信息（§10.6），
错误状态（例如，到达 输入的结尾(end-of-input)了吗？），以及所使用缓冲的类型。
另外，用户可以设置这些状态，以表示某个错误的发生（§10.5）
还可以清除该状态，如果它不是严重问题。
例如，可以想象<code>read_ints()</code>的某个版本接收一个终止字符串：</p>
<pre><code class="lang-cpp"><span class="hljs-function">vector&lt;<span class="hljs-type">int</span>&gt; <span class="hljs-title">read_ints</span><span class="hljs-params">(istream&amp; is, <span class="hljs-type">const</span> string&amp; terminator)</span>
</span>{
    vector&lt;<span class="hljs-type">int</span>&gt; res;
    <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i; is &gt;&gt; i; )
        res.<span class="hljs-built_in">push_back</span>(i);

    <span class="hljs-keyword">if</span> (is.<span class="hljs-built_in">eof</span>())       <span class="hljs-comment">// 很好：文件末尾</span>
        <span class="hljs-keyword">return</span> res;

    <span class="hljs-keyword">if</span> (is.<span class="hljs-built_in">fail</span>()) {    <span class="hljs-comment">// 没能读取一个 int；它是终止符吗？</span>
        is.<span class="hljs-built_in">clear</span>();     <span class="hljs-comment">// 重置状态为 good()</span>
        is.<span class="hljs-built_in">unget</span>();     <span class="hljs-comment">// 把这个非数字字符放回到流里</span>
        string s;
        <span class="hljs-keyword">if</span> (cin&gt;&gt;s &amp;&amp; s==terminator)
            <span class="hljs-keyword">return</span> res;
        cin.<span class="hljs-built_in">setstate</span>(ios_base::failbit);    <span class="hljs-comment">// 把 fail() 添加到 cin 的状态</span>
    }
    <span class="hljs-keyword">return</span> res;
}
<span class="hljs-keyword">auto</span> v = <span class="hljs-built_in">read_ints</span>(cin,<span class="hljs-string">&quot;stop&quot;</span>);
</code></pre>
<p><a class="en-page-number" id="128"></a></p>
<h2 id="10.5">10.5 用户定义类型的I/O </h2>
<p>除了针对内建类型和<code>string</code>的 I/O，
<code>iostream</code>库还允许程序员为他们自己的类型定义I/O。
例如，考虑一个简单的类型<code>Entry</code>，可用它表示电话薄的一个条目：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Entry</span> {
    string name;
    <span class="hljs-type">int</span> number;
};
</code></pre>
<p>可以定义一个简单的输出操作符，使用 <em>{&quot;name&quot;,number}</em> 格式将其打印出来，
该格式与代码中初始化它的时候类似：</p>
<pre><code class="lang-cpp">ostream&amp; <span class="hljs-keyword">operator</span>&lt;&lt;(ostream&amp; os, <span class="hljs-type">const</span> Entry&amp; e)
{
    <span class="hljs-keyword">return</span> os &lt;&lt; <span class="hljs-string">&quot;{\&quot;&quot;</span> &lt;&lt; e.name &lt;&lt; <span class="hljs-string">&quot;\&quot;, &quot;</span> &lt;&lt; e.number &lt;&lt; <span class="hljs-string">&quot;}&quot;</span>;
}
</code></pre>
<p>用户定义的输出操作符接收输出流（传引用）作为第一个参数，并返回这个流作为结果。</p>
<p>对应的输入操作符相对复杂一些，因为此操作需要检查格式的正确性，并处理错误：</p>
<pre><code class="lang-cpp">istream&amp; <span class="hljs-keyword">operator</span>&gt;&gt;(istream&amp; is, Entry&amp; e)
    <span class="hljs-comment">// 读取 { &quot;name&quot; , number } 对。注意：使用 { &quot; &quot; 和 } 进行格式化</span>
{
    <span class="hljs-type">char</span> c, c2;
    <span class="hljs-keyword">if</span> (is&gt;&gt;c &amp;&amp; c==<span class="hljs-string">&apos;{&apos;</span> &amp;&amp; is&gt;&gt;c2 &amp;&amp; c2==<span class="hljs-string">&apos;&quot;&apos;</span>) { <span class="hljs-comment">// 以 { &quot; 开头</span>
        string name;                    <span class="hljs-comment">// 字符串的默认值是空字符串： &quot;&quot;</span>
        <span class="hljs-keyword">while</span> (is.<span class="hljs-built_in">get</span>(c) &amp;&amp; c!=<span class="hljs-string">&apos;&quot;&apos;</span>)     <span class="hljs-comment">// &quot; 前的所有内容都是 name 部分</span>
            name+=c;

        <span class="hljs-keyword">if</span> (is&gt;&gt;c &amp;&amp; c==<span class="hljs-string">&apos;,&apos;</span>) {
            <span class="hljs-type">int</span> number = <span class="hljs-number">0</span>;
            <span class="hljs-keyword">if</span> (is&gt;&gt;number&gt;&gt;c &amp;&amp; c==<span class="hljs-string">&apos;}&apos;</span>) {  <span class="hljs-comment">// 读取 number 和一个 }</span>
                e = {name,number};          <span class="hljs-comment">// 赋值给这条记录</span>
                <span class="hljs-keyword">return</span> is;
            }
        }
    }
    is.<span class="hljs-built_in">setstate</span>(ios_base::failbit);     <span class="hljs-comment">// 在流中标记 失败</span>
    <span class="hljs-keyword">return</span> is;
}
</code></pre>
<p>输入操作返回一个指向其<code>istream</code>的引用，可用于检测操作是否成功。
例如：作为条件使用时，<code>is&gt;&gt;c</code>表示“是否成功从<code>is</code>读取一个<code>char</code>置入了<code>c</code>？”</p>
<p><code>is&gt;&gt;c</code>默认会跳过空白字符，但是<code>is.get(c)</code>不会，
因此这个<code>Entry</code>-输入 操作符忽略（跳过）name字符串外的空白字符，
但是不会忽略name中的。例如：</p>
<p><a class="en-page-number" id="129"></a></p>
<pre><code class="lang-text">{ &quot;John Marwood Cleese&quot;, 123456     }
{&quot;Michael Edward Palin&quot;, 987654}
</code></pre>
<p>可以这样从输入读取这对值进入一个<code>Entry</code>：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">for</span> (Entry ee; cin&gt;&gt;ee; )   <span class="hljs-comment">// 从 cin 读入 ee</span>
    cout &lt;&lt; ee &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;     <span class="hljs-comment">// 把 ee 写出到 cout</span>
</code></pre>
<p>输出是：</p>
<pre><code class="lang-text">{&quot;John Marwood Cleese&quot;, 123456}
{&quot;Michael Edward Palin&quot;, 987654}
</code></pre>
<p>有关在字符流中识别模式的更系统化的技术（正则表达式匹配），请参阅 §9.4。</p>
<h2 id="10.6">10.6 格式化 </h2>
<p><code>iostream</code>库提为控制输入和输出格式化供了大量的控制操作。
最简单的格式化控制叫做<em>操控符（manipulator）</em>，
可见于<code>&lt;ios&gt;</code>、<code>&lt;istrean&gt;</code>、<code>&lt;ostream&gt;</code>和
<code>&lt;iomanip&gt;</code>（针对接收参数的操控符）。
例如，可以将整数作为（默认的）十进制、八进制或十六进制数字输出：</p>
<pre><code class="lang-cpp">cout &lt;&lt; <span class="hljs-number">1234</span> &lt;&lt; <span class="hljs-string">&apos;,&apos;</span> &lt;&lt; hex &lt;&lt; <span class="hljs-number">1234</span> &lt;&lt; <span class="hljs-string">&apos;,&apos;</span> &lt;&lt; oct &lt;&lt; <span class="hljs-number">1234</span> &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;   <span class="hljs-comment">// 打印1234,4d2,2322</span>
</code></pre>
<p>可以显式为浮点数设置输出格式：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">constexpr</span> <span class="hljs-type">double</span> d = <span class="hljs-number">123.456</span>;

cout &lt;&lt; d &lt;&lt; <span class="hljs-string">&quot;; &quot;</span>                   <span class="hljs-comment">// 为 d 使用默认格式</span>
     &lt;&lt; scientific &lt;&lt; d &lt;&lt; <span class="hljs-string">&quot;; &quot;</span>     <span class="hljs-comment">// 为 d 使用 1.123e2 风格的格式</span>
     &lt;&lt; hexfloat &lt;&lt; d &lt;&lt; <span class="hljs-string">&quot;; &quot;</span>       <span class="hljs-comment">// 为 d 使用十六进制表示法</span>
     &lt;&lt; fixed &lt;&lt; d &lt;&lt; <span class="hljs-string">&quot;; &quot;</span>          <span class="hljs-comment">// 为 d 使用123.456 风格的格式</span>
     &lt;&lt; defaultfloat &lt;&lt; d &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;  <span class="hljs-comment">// 为 d 使用默认格式</span>
</code></pre>
<p>这将输出：</p>
<pre><code class="lang-text">123.456; 1.234560e+002; 0x1.edd2f2p+6; 123.456000; 123.456
</code></pre>
<p>浮点数的精度是个决定其显示位数的整数：</p>
<ul>
<li><em>常规（general）</em>格式（<code>defaultfloat</code>）让编译器选择格式去呈现某个值，
  以便该格式在可用空间内能最好地展示其值。此精度可指定最大位数。</li>
<li><em>科学计数法（scientific）</em>格式以小数点前一位数字和一个幂呈现某个值。
  此精度可指定小数点后数字的最大位数。</li>
<li><em>固定（fixed）</em>格式以整数部分后跟一个小数点再跟小数部分呈现某个值，
  此精度可指定小数点后数字的最大位数。</li>
</ul>
<p>浮点数会被四舍五入而不是截断，<code>precision()</code>不会影响整数的输出。例如：</p>
<p><a class="en-page-number" id="130"></a></p>
<pre><code class="lang-cpp">cout.<span class="hljs-built_in">precision</span>(<span class="hljs-number">8</span>);
cout &lt;&lt; <span class="hljs-number">1234.56789</span> &lt;&lt; <span class="hljs-string">&apos; &apos;</span> &lt;&lt; <span class="hljs-number">1234.56789</span> &lt;&lt; <span class="hljs-string">&apos; &apos;</span> &lt;&lt; <span class="hljs-number">123456</span> &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;

cout.<span class="hljs-built_in">precision</span>(<span class="hljs-number">4</span>);
cout &lt;&lt; <span class="hljs-number">1234.56789</span> &lt;&lt; <span class="hljs-string">&apos; &apos;</span> &lt;&lt; <span class="hljs-number">1234.56789</span> &lt;&lt; <span class="hljs-string">&apos; &apos;</span> &lt;&lt; <span class="hljs-number">123456</span> &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
cout &lt;&lt; <span class="hljs-number">1234.56789</span> &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
</code></pre>
<p>这将输出：</p>
<pre><code class="lang-text">1234.5679 1234.5679 123456
1235 1235 123456
1235
</code></pre>
<p>这些浮点数操控符是“有粘性的（sticky）”；
就是说，它们的效果会对后续浮点数操作都生效。</p>
<h2 id="10.7">10.7 文件流 </h2>
<p>在<code>&lt;fstream&gt;</code>中，标准库提供了针对文件的输入和输出：</p>
<ul>
<li><code>ifstream</code> 用于从一个文件进行读取</li>
<li><code>ofstream</code> 用于向一个文件进行写入</li>
<li><code>fstream</code> 用于对一个文件进行读取和写入</li>
</ul>
<p>例如：</p>
<pre><code class="lang-cpp">ofstream ofs {<span class="hljs-string">&quot;target&quot;</span>}; <span class="hljs-comment">// “o” 的意思是 “输出（output）”</span>
<span class="hljs-keyword">if</span> (!ofs)
    <span class="hljs-built_in">error</span>(<span class="hljs-string">&quot;couldn&apos;t open &apos;target&apos; for writing&quot;</span>);
</code></pre>
<p>测试一个文件流是否正确打开，通常要检测其状态。</p>
<pre><code class="lang-cpp">ifstream ifs {<span class="hljs-string">&quot;source&quot;</span>}; <span class="hljs-comment">// “i” 的意思是 “输入（input）”</span>
<span class="hljs-keyword">if</span> (!ifs)
    <span class="hljs-built_in">error</span>(<span class="hljs-string">&quot;couldn&apos;t open &apos;source&apos; for reading&quot;</span>);
</code></pre>
<p>假设这些测试都成功了，那么<code>ofs</code>可以像普通<code>ostream</code>（类似<code>cout</code>）那样使用，
<code>ifs</code>可以像普通<code>istream</code>（类似<code>cin</code>）那样使用。</p>
<p>文件定位，以及更详尽的文件打开控制都行得通，但这些不在本书的范畴里。
对于文件名和文件系统的操作，请参阅 §10.10。</p>
<h2 id="10.8">10.8 字符串流 </h2>
<p>在<code>&lt;sstream&gt;</code>中，标准库提供了针对<code>string</code>的写入和读出的操作：</p>
<ul>
<li><code>istringstream</code> 用于从一个<code>string</code>进行读取</li>
<li><code>ostringstream</code> 用于向一个<code>string</code>进行写入</li>
<li><code>stringstream</code> 用于对一个<code>string</code>进行读取和写入。</li>
</ul>
<p>例如：</p>
<p><a class="en-page-number" id="131"></a></p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">test</span><span class="hljs-params">()</span>
</span>{
    ostringstream oss;
    oss &lt;&lt; <span class="hljs-string">&quot;{temperature,&quot;</span> &lt;&lt; scientific &lt;&lt; <span class="hljs-number">123.4567890</span> &lt;&lt; <span class="hljs-string">&quot;}&quot;</span>;
    cout &lt;&lt; oss.<span class="hljs-built_in">str</span>() &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
}
</code></pre>
<p><code>ostringstream</code>的结果可以通过<code>str()</code>进行读取。
<code>ostringstream</code>的用法通常是在把结果交给GUI之前进行格式化。
类似地，从GUI接收的字符串可置于<code>istringstream</code>中进行格式化读取（§10.3）。</p>
<p><code>stringstream</code>即可用于读取也可用于输出。例如，可以定义一个操作，
对于任何可呈现为<code>string</code>的类型，将其转换为另一个可呈现为<code>string</code>的类型：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">typename</span> Target </span>=string, <span class="hljs-keyword">typename</span> Source =string&gt;
Target <span class="hljs-built_in">to</span>(Source arg)           <span class="hljs-comment">// 从 Source 转换到 Target</span>
{
    stringstream interpreter;
    Target result;

    <span class="hljs-keyword">if</span> (!(interpreter &lt;&lt; arg)               <span class="hljs-comment">// 把 arg 写入到流</span>
        || !(interpreter &gt;&gt; result)         <span class="hljs-comment">// 从流里读取结果</span>
        || !(interpreter &gt;&gt; std::ws).<span class="hljs-built_in">eof</span>()) <span class="hljs-comment">// 还有东西剩在流中吗？</span>
        <span class="hljs-keyword">throw</span> runtime_error{<span class="hljs-string">&quot;to&lt;&gt;() failed&quot;</span>};

    <span class="hljs-keyword">return</span> result;
}
</code></pre>
<p>只有在无法被推断出或者没有默认值的情况下，模板参数才需要显式指定，所以可以这样写：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">auto</span> x1 = <span class="hljs-built_in">to</span>&lt;string,<span class="hljs-type">double</span>&gt;(<span class="hljs-number">1.2</span>);   <span class="hljs-comment">// 非常明确（并且多余）</span>
<span class="hljs-keyword">auto</span> x2 = <span class="hljs-built_in">to</span>&lt;string&gt;(<span class="hljs-number">1.2</span>);          <span class="hljs-comment">// Source 被推断为 double</span>
<span class="hljs-keyword">auto</span> x3 = to&lt;&gt;(<span class="hljs-number">1.2</span>);                <span class="hljs-comment">// Target 使用了默认的 string； Source 被推断为 double</span>
<span class="hljs-keyword">auto</span> x4 = <span class="hljs-built_in">to</span>(<span class="hljs-number">1.2</span>);                  <span class="hljs-comment">// &lt;&gt; 冗余了；</span>
                                    <span class="hljs-comment">// Target 使用了默认的 string； Source 被推断为 double</span>
</code></pre>
<p>如果所有函数模板参数都有默认值，<code>&lt;&gt;</code>可以省略。</p>
<p>我认为这是个有关借助语言特性和标准库构件达成通用性和易用性的好例子。</p>
<h2 id="10.9">10.9 C-风格I/O </h2>
<p>C++标准库也支持C标准库的I/O，包括<code>printf()</code>和<code>scanf()</code>。
以特定的安全视角来看，大量应用这个库是不安全的，因此我不推荐用它们。
特别是，它们在输入的安全和便利性方面荆棘密布。
它们还不支持用户定义类型。
如果你<em>不</em>使用C风格I/O并且对I/O的性能锱铢必较，就调用：</p>
<p><a class="en-page-number" id="132"></a></p>
<pre><code class="lang-cpp">ios_base::<span class="hljs-built_in">sync_with_stdio</span>(<span class="hljs-literal">false</span>); <span class="hljs-comment">// 避免显著的开销</span>
</code></pre>
<p>没有这个调用，<code>iostream</code>会为了兼容C风格I/O而被显著拖慢。</p>
<h2 id="10.10">10.10 文件系统 </h2>
<p>多数系统都有一个<em>文件系统（file system）</em>的概念，
以<em>文件（file）</em>的形式对持久化的信息提供访问。
很不幸，文件系统的属性和操作它们的方式五花八门。
为应对这个问题，<code>&lt;filesystem&gt;</code>
中的文件系统库为多数文件系统的多数构件提供了统一的接口。
借助<code>&lt;filesystem&gt;</code>，我们能够可移植地：</p>
<ul>
<li>表示文件系统路径并在其中漫游</li>
<li>检查文件类型以及与之关联的权限</li>
</ul>
<p>文件系统库可以处理 unicode，但其实现方式的解释则不在本书范畴内。
有关更详尽的信息，我推荐 cppreference[Cppreference]
和 Boost文件系统文档[Boost]。</p>
<p>考虑一个例子：</p>
<pre><code class="lang-cpp">path f = <span class="hljs-string">&quot;dir/hypothetical.cpp&quot;</span>;    <span class="hljs-comment">// 命名一个文件</span>

<span class="hljs-built_in">assert</span>(<span class="hljs-built_in">exists</span>(f));          <span class="hljs-comment">// f 必须存在</span>

<span class="hljs-keyword">if</span> (<span class="hljs-built_in">is_regular_file</span>(f))     <span class="hljs-comment">// f 是个普通文件吗？</span>
    cout &lt;&lt; f &lt;&lt; <span class="hljs-string">&quot; is a file; its size is &quot;</span> &lt;&lt; <span class="hljs-built_in">file_size</span>(f) &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
</code></pre>
<p>注意，操作文件系统的程序通常跟其它程序运行在同一台电脑上。
因此，文件系统的内容可能在两条命令之间发生变化。
例如，尽管我们事先精心地确保了<code>f</code>存在，但是在运行到下一行，
当我们询问<code>f</code>是否为普通文件的时候它可能就没了。</p>
<p><code>path</code>是个相当复杂的类，足以处理本地字符集以及大量操作系统的习惯。
特别是，它能处理来自命令行的文件名，就像示例中<code>main()</code>展示的那样：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span>* argv[])</span>
</span>{
    <span class="hljs-keyword">if</span> (argc &lt; <span class="hljs-number">2</span>) {
        cerr &lt;&lt; <span class="hljs-string">&quot;arguments expected\n&quot;</span>;
        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
    }

    path p {argv[<span class="hljs-number">1</span>]};   <span class="hljs-comment">// 从命令行参数创建一个 path</span>

    cout &lt;&lt; p &lt;&lt; <span class="hljs-string">&quot; &quot;</span> &lt;&lt; <span class="hljs-built_in">exists</span>(p) &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>; <span class="hljs-comment">// 注意：path可以像字符串那样打印出来</span>
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>在使用之前，<code>path</code>不会检测有效性。
就算到使用的时候，其有效性也取决于该程序所运行系统的习惯。</p>
<p><a class="en-page-number" id="133"></a></p>
<p>显而易见，<code>path</code>可用来打开一个文件</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">use</span><span class="hljs-params">(path p)</span>
</span>{
    ofstream f {p};
    <span class="hljs-keyword">if</span> (!f) <span class="hljs-built_in">error</span>(<span class="hljs-string">&quot;bad file name: &quot;</span>, p);
    f &lt;&lt; <span class="hljs-string">&quot;Hello, file!&quot;</span>;
}
</code></pre>
<p>除了<code>path</code>，<code>&lt;filesystem&gt;</code>还提供了用于遍历目录以及查询文件属性的类型：</p>
<table style="width:80%;margin-left:auto;margin-right:auto;">
    <tbody>
        <tr>
            <th colspan="2" style="text-align: center"><strong>文件系统中的类型（部分）</strong></th>
        </tr>
        <tr>
            <td style="width:35%"><code>path</code></td>
            <td>目录路径</td>
        </tr>
        <tr>
            <td><code>filesystem_error</code></td>
            <td>文件系统异常</td>
        </tr>
        <tr>
            <td><code>directory_entry</code></td>
            <td>目录入口</td>
        </tr>
        <tr>
            <td><code>directory_iterator</code></td>
            <td>用于遍历一个目录</td>
        </tr>
        <tr>
            <td><code>recursive_directory_iterator</code></td>
            <td>用于遍历一个目录和其子目录</td>
        </tr>
    </tbody>
</table>

<p>考虑一个简单但不失真实性的例子：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print_directory</span><span class="hljs-params">(path p)</span>
<span class="hljs-keyword">try</span>
</span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">is_directory</span>(p)) {
        cout &lt;&lt; p &lt;&lt; <span class="hljs-string">&quot;:\n&quot;</span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-type">const</span> directory_entry&amp; x : directory_iterator{p})
            cout &lt;&lt; <span class="hljs-string">&quot; &quot;</span> &lt;&lt; x.<span class="hljs-built_in">path</span>() &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
    }
}
<span class="hljs-built_in">catch</span> (<span class="hljs-type">const</span> filesystem_error&amp; ex) {
    cerr &lt;&lt; ex.<span class="hljs-built_in">what</span>() &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
}
</code></pre>
<p>字符串可以隐式地转换成<code>path</code>，因此可以这样运用<code>print_directory</code>：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">use</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-built_in">print_directory</span>(<span class="hljs-string">&quot;.&quot;</span>);       <span class="hljs-comment">// 当前目录</span>
    <span class="hljs-built_in">print_directory</span>(<span class="hljs-string">&quot;..&quot;</span>);      <span class="hljs-comment">// 父目录</span>
    <span class="hljs-built_in">print_directory</span>(<span class="hljs-string">&quot;/&quot;</span>);       <span class="hljs-comment">// Unix 根目录</span>
    <span class="hljs-built_in">print_directory</span>(<span class="hljs-string">&quot;c:&quot;</span>);      <span class="hljs-comment">// Windows C 盘</span>

    <span class="hljs-keyword">for</span> (string s; cin&gt;&gt;s; )
        <span class="hljs-built_in">print_directory</span>(s);
}
</code></pre>
<p>如果我也想列出子目录，应该用<code>recursive_directory_iterator{p}</code>。
如果我想以字典序列出条目，就该把这些<code>path</code>复制到一个<code>vector</code>中并排序后输出。</p>
<p><a class="en-page-number" id="134"></a></p>
<p><code>path</code>类提供很多常见且有用的操作：</p>
<table style="width:90%;margin-left:auto;margin-right:auto;">
    <tbody>
        <tr>
            <th colspan="2" style="text-align: center">
                <strong>路径操作（部分）</strong><br>
                <code>p</code>和<code>p2</code>都是<code>path</code>
            </th>
        </tr>
        <tr>
            <td style="width:35%"><code>value_type</code></td>
            <td>
                本地系统用于文件系统编码的字符类型：<br>
                POSIX上是<code>char</code>，Windows上是<code>wchar_t</code>
            </td>
        </tr>
        <tr>
            <td><code>string_type</code></td>
            <td><code>std::basic_string&lt;value_type&gt;</code></td>
        </tr>
        <tr>
            <td><code>const_iterator</code></td>
            <td><code>value_type</code>为<code>path</code>的<code>const</code> BidirectionalIterator</td>
        </tr>
        <tr>
            <td><code>iterator</code></td>
            <td><code>const_iterator</code>的别名</td>
        </tr>
        <tr>
            <td></td><td></td>
        </tr>
        <tr>
            <td><code>p=p2</code></td>
            <td>把<code>p2</code>赋值给<code>p</code></td>
        </tr>
        <tr>
            <td><code>p/=p2</code></td>
            <td>把<code>p</code>和<code>p2</code>用文件名分隔符(默认是/)连接</td>
        </tr>
        <tr>
            <td><code>p+p2</code></td>
            <td>把<code>p</code>和<code>p2</code>连接（无分隔符）</td>
        </tr>
        <tr>
            <td><code>p.native()</code></td>
            <td><code>p</code>的本地系统格式</td>
        </tr>
        <tr>
            <td><code>p.string()</code></td>
            <td><code>p</code>以其所在的本地系统格式表示的<code>string</code></td>
        </tr>
        <tr>
            <td><code>p.generic_string()</code></td>
            <td><code>p</code>以通用格式表示的<code>string</code></td>
        </tr>
        <tr>
            <td><code>p.filename()</code></td>
            <td><code>p</code>的文件名部分</td>
        </tr>
        <tr>
            <td><code>p.stem()</code></td>
            <td><code>p</code>的主干部分（不带扩展名的文件名——译注）</td>
        </tr>
        <tr>
            <td><code>p.extension()</code></td>
            <td><code>p</code>的文件扩展名部分</td>
        </tr>
        <tr>
            <td><code>p.begin()</code></td>
            <td><code>p</code>的元素序列的起始</td>
        </tr>
        <tr>
            <td><code>p.end()</code></td>
            <td><code>p</code>的元素序列的终止</td>
        </tr>
        <tr>
            <td><code>p==p2</code>，<code>p!=p2</code></td>
            <td><code>p</code>和<code>p2</code>的相等、不等性判定</td>
        </tr>
        <tr>
            <td><code>p&lt;p2</code>，<code>p&lt;=p2</code>，<code>p&gt;p2</code>，<code>p&gt;=p2</code></td>
            <td>字典序比对</td>
        </tr>
        <tr>
            <td><code>is&gt;&gt;p</code>，<code>os&lt;&lt;p</code></td>
            <td>进入/取出<code>p</code>的流I/O操作</td>
        </tr>
        <tr>
            <td><code>u8path(s)</code></td>
            <td>以UTF-8编码的源字符串<code>s</code>构造一个路径</td>
        </tr>
    </tbody>
</table>

<p>例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">test</span><span class="hljs-params">(path p)</span>
</span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">is_directory</span>(p)) {
        cout &lt;&lt; p &lt;&lt; <span class="hljs-string">&quot;:\n&quot;</span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-type">const</span> directory_entry&amp; x : <span class="hljs-built_in">directory_iterator</span>(p)) {
            <span class="hljs-type">const</span> path&amp; f = x;      <span class="hljs-comment">// 指向一个目录条目的路径部分</span>
            <span class="hljs-keyword">if</span> (f.<span class="hljs-built_in">extension</span>() == <span class="hljs-string">&quot;.exe&quot;</span>)
                cout &lt;&lt; f.<span class="hljs-built_in">stem</span>() &lt;&lt; <span class="hljs-string">&quot; is a Windows executable\n&quot;</span>;
            <span class="hljs-keyword">else</span> {
                string n = f.<span class="hljs-built_in">extension</span>().<span class="hljs-built_in">string</span>();
                <span class="hljs-keyword">if</span> (n == <span class="hljs-string">&quot;.cpp&quot;</span> || n == <span class="hljs-string">&quot;.C&quot;</span> || n == <span class="hljs-string">&quot;.cxx&quot;</span>)
                    cout &lt;&lt; f.<span class="hljs-built_in">stem</span>() &lt;&lt; <span class="hljs-string">&quot; is a C++ source file\n&quot;</span>;
            }
        }
    }
}
</code></pre>
<p>我们把<code>path</code>当作一个字符串（即：f.extension）使用，
还可以从<code>path</code>中提取各种类型的字符串（即：f.extension().string()）。</p>
<p><a class="en-page-number" id="135"></a></p>
<p>请当心，命名习惯、自然语言以及字符串编码的复杂度非常高。
文件系统库的抽象提供了可移植性与极大的简化。</p>
<table style="margin-left:auto;margin-right:auto;">
    <tbody>
        <tr>
            <th colspan="2" style="text-align: center">
                <strong>文件系统操作（部分）</strong><br>
                <code>p</code>，<code>p1</code>和<code>p2</code>都是<code>path</code>；
                <code>e</code>是个<code>error_code</code>；
                <code>b</code>是个标志成功或失败的布尔值
            </th>
        </tr>
        <tr>
            <td style="width:35%"><code>exists(p)</code></td>
            <td>
                <code>p</code>指向的文件系统对象是否存在？
            </td>
        </tr>
        <tr>
            <td><code>copy(p1,p2)</code></td>
            <td>把<code>p1</code>的文件或目录复制到<code>p2</code>；将错误以异常形式报告</td>
        </tr>
        <tr>
            <td><code>copy(p1,p2,e)</code></td>
            <td>复制的文件或目录；将错误以错误码形式报告</td>
        </tr>
        <tr>
            <td><code>b=copy_file(p1,p2)</code></td>
            <td>把<code>p1</code>的文件内容复制到<code>p2</code>；将错误以异常形式报告</td>
        </tr>
        <tr>
            <td><code>b=create_directory(p)</code></td>
            <td>创建名为<code>p</code>的新目录；通向<code>p</code>的中间目录必须存在</td>
        </tr>
        <tr>
            <td><code>b=create_directories(p)</code></td>
            <td>创建名为<code>p</code>的新目录；通向<code>p</code>的中间目录一并创建</td>
        </tr>
        <tr>
            <td><code>p=current_path()</code></td>
            <td><code>p</code>是当前工作目录</td>
        </tr>
        <tr>
            <td><code>current_path(p)</code></td>
            <td>让<code>p</code>成为当前工作目录</td>
        </tr>
        <tr>
            <td><code>s=file_size(p)</code></td>
            <td><code>s</code>是<code>p</code>的字节数</td>
        </tr>
        <tr>
            <td><code>b=remove(p)</code></td>
            <td>如果<code>p</code>是个文件或空目录，移除它</td>
        </tr>
    </tbody>
</table>

<p>许多操作都有接收额外参数的重载，例如操作系统权限。
这类操作大大超出了本书的范畴，所以在需要用它的时候去搜索吧。</p>
<p>像<code>copy()</code>一样，所有的操作都有两个版本：</p>
<ul>
<li>像表中列出那样的基础版本，即<code>exists(p)</code>。
  如果操作失败，函数将抛出<code>filesystem_error</code>。</li>
<li>带有额外<code>error_code</code>参数的版本，即<code>exists(p,e)</code>。检测<code>e</code>查看操作是否成功。</li>
</ul>
<p>如果在常规使用中预期会频繁失败，请使用错误码，
如果出错是异常状况，就请使用抛出异常的操作。</p>
<p>通常，使用查询函数是检查文件属性最简单、最直接的方式。
<code>&lt;filesystem&gt;</code>库略知几个常见的文件类型，并将其余的归类为“其它”：</p>
<table style="width:90%;margin-left:auto;margin-right:auto;">
    <tbody>
        <tr>
            <th colspan="2" style="text-align: center">
                <strong>文件类型</strong><br>
                <code>f</code>是个<code>path</code>或者<code>file_status</code>
            </th>
        </tr>
        <tr>
            <td style="width:35%"><code>is_block_file(f)</code></td>
            <td><code>f</code>是个块设备吗？</td>
        </tr>
        <tr>
            <td><code>is_character_file(f)</code></td>
            <td><code>f</code>是个字符设备吗？</td>
        </tr>
        <tr>
            <td><code>is_directory(f)</code></td>
            <td><code>f</code>是个目录吗？</td>
        </tr>
        <tr>
            <td><code>is_empty(f)</code></td>
            <td><code>f</code>是个空的文件或目录吗？</td>
        </tr>
        <tr>
            <td><code>is_fifo(f)</code></td>
            <td><code>f</code>是个命名管道吗？</td>
        </tr>
        <tr>
            <td><code>is_other(f)</code></td>
            <td><code>f</code>是其他类型的文件吗？</td>
        </tr>
        <tr>
            <td><code>is_regular_file(f)</code></td>
            <td><code>f</code>是个常规（普通）文件吗？</td>
        </tr>
        <tr>
            <td><code>is_socket(f)</code></td>
            <td><code>f</code>是个命名的IPC socket 吗？</td>
        </tr>
        <tr>
            <td><code>is_symlink(f)</code></td>
            <td><code>f</code>是个符号链接吗？</td>
        </tr>
        <tr>
            <td><code>status_known(f)</code></td>
            <td><code>f</code>的文件状态已知吗？</td>
        </tr>
    </tbody>
</table>

<p><a class="en-page-number" id="136"></a></p>
<h2 id="10.11">10.11 忠告 </h2>
<ul>
<li>[1] <code>iostream</code> 是类型安全、大小写敏感并可扩展的；§10.1。</li>
<li>[2] 只在不得不的时候再用字节级别的输入；§10.3； [CG: SL.io.1]。</li>
<li>[3] 在读取的时候，永远该考虑格式有问题的输入；§10.3； [CG: SL.io.2]。</li>
<li>[4] 避免使用<code>endl</code>（如果你不知道什么是<code>endl</code>，你没漏读任何内容）；[CG: SL.io.50]。</li>
<li>[5] 对于用户定义类型，如果其值是有意义文本形式，
  请给它定义<code>&lt;&lt;</code>和<code>&gt;&gt;</code>；§10.1；§10.2；§10.3。</li>
<li>[6] 用<code>cout</code>输出常规内容，<code>cerr</code>输出错误信息；§10.1。</li>
<li>[7] 针对普通字符和宽字符，有不同的<code>iostream</code>，
  你还可以为任意字符类型定义<code>iostream</code>；§10.1。</li>
<li>[8] 二进制 I/O 是受支持的；§10.1。</li>
<li>[9] 对标准 I/O 流有标准的<code>iostream</code>，
  文件和<code>string</code>也都有对应的标准流；§10.2；§10.3；§10.7；§10.8。</li>
<li>[10] 为简明的符号使用链式 <code>&lt;&lt;</code>；§10.2。</li>
<li>[11] 为简明的符号使用链式 <code>&gt;&gt;</code>；§10.3。</li>
<li>[12] 往<code>string</code>里输入不会导致溢出；§10.3。</li>
<li>[13] 默认情况下，<code>&gt;&gt;</code>会跳过起始的空白字符；§10.3。</li>
<li>[14] 对于可能恢复处理的I/O错误，使用流状态<code>fail</code>去处理；§10.4。</li>
<li>[15] 可以为你自定义的类型定义<code>&lt;&lt;</code>和<code>&gt;&gt;</code>操作符；§10.5。</li>
<li>[16] 不需要为新添加的<code>&lt;&lt;</code>和<code>&gt;&gt;</code>修改<code>istream</code>和<code>ostream</code>；§10.5。</li>
<li>[17] 使用操控符去控制格式化；§10.6。</li>
<li>[18] <code>precision()</code>规格会被应用到其后所有的浮点数输出操作；§10.6。</li>
<li>[19] 浮点数格式化规格（即<code>scientific</code>）
  会被应用到其后所有的浮点数输出操作；§10.6。</li>
<li>[20] 需要使用标准操控符时就<code>#include &lt;ios&gt;</code>；§10.6。</li>
<li>[21] 需要使用带参数的标准操控符时就<code>#include &lt;iomanip&gt;</code>；§10.6。</li>
<li>[22] 别尝试去复制文件流。</li>
<li>[23] 在使用前，请记得检查文件流确定关联到了某个文件；§10.7。</li>
<li>[24] 对内存中的格式化，请使用<code>stringstream</code>；§10.8。</li>
<li>[25] 可以在任何具有字符串表示的两个类型之间定义转换操作；§10.8。</li>
<li>[26] C-风格的I/O操作不是类型安全的；§10.9。</li>
<li>[27] 除非你需要 printf 相关的函数，否则应该调用
  <code>ios_base::sync_with_stdio(false)</code>；§10.9； [CG: SL.io.10]。</li>
<li>[28] 使用<code>&lt;filesystem&gt;</code>而非特定操作系统的接口；§10.10。</li>
</ul>
<blockquote id="fn_1">
<sup>1</sup>. 这句话的原文是“What you see is all you get.”，没找到出处，可见于他的维基百科页面 <a href="https://en.wikipedia.org/wiki/Brian_Kernighan" target="_blank">https://en.wikipedia.org/wiki/Brian_Kernighan</a> ，未找到官方翻译，有一个译法是 <a href="https://www.ituring.com.cn/article/17869" target="_blank"><strong>所见即全部所得</strong></a>，但我理解这里强调的是“某些内容被抛弃”，故按此翻译。 —— 译者注<a href="#reffn_1" title="Jump back to footnote [1] in the text."> ↩</a>
</blockquote>

<script>console.log(window.location.pathname)</script>
<div id="disqus_thread"></div>
<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/
/*
var disqus_config = function () {
this.page.url = window.location.href;
this.page.identifier = window.location.pathname;
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://a-tour-of-cpp-2nd-cn.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" target="_blank">comments powered by Disqus.</a></noscript>
                                
    

                                </section>
                            
    </div>
    <div class="search-results">
        <div class="has-results">
            
            <h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
            <ul class="search-results-list"></ul>
            
        </div>
        <div class="no-results">
            
            <h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
            
        </div>
    </div>
</div>

                        </div>
                    </div>
                
            </div>

            
                
                <a href="ch09.html" class="navigation navigation-prev " aria-label="Previous page: 9 字符串和正则表达式">
                    <i class="fa fa-angle-left"></i>
                </a>
                
                
                <a href="ch11.html" class="navigation navigation-next " aria-label="Next page: 11 容器">
                    <i class="fa fa-angle-right"></i>
                </a>
                
            
        
    </div>

    <script>
        var gitbook = gitbook || [];
        gitbook.push(function() {
            gitbook.page.hasChanged({"page":{"ch":10,"title":"10 输入输出","level":"1.12","depth":1,"next":{"title":"11 容器","level":"1.13","depth":1,"path":"ch11.md","ref":"ch11.md","articles":[]},"previous":{"title":"9 字符串和正则表达式","level":"1.11","depth":1,"path":"ch09.md","ref":"ch09.md","articles":[]},"dir":"ltr"},"config":{"plugins":["@dogatana/page-toc-button","@dogatana/back-to-top-button","copy-code-button","forkmegithub","disqus-legacy"],"root":"./src","styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"@dogatana/back-to-top-button":{},"styles":{"website":"styles/website.css"},"search":{},"@dogatana/page-toc-button":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"fontsettings":{"theme":"white","family":"sans","size":2},"highlight":{},"disqus-legacy":{"shortname":"a-tour-of-cpp-2nd-cn"},"copy-code-button":{},"forkmegithub":{"color":"orange","url":"https://github.com/windsting/a-tour-of-cpp-2nd-cn"},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","author":"Windsting","pdf":{"pageNumbers":true,"fontSize":14,"fontFamily":"Arial","paperSize":"a5","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56},"embedFonts":false},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"title":"C++导览 第二版 简体中文版","language":"zh-hans","links":{"sidebar":{"Github Link":"https://github.com/windsting/a-tour-of-cpp-2nd-cn"}},"gitbook":"*","description":"A Tour of C++ (第二版) 非官方中译本"},"file":{"path":"ch10.md","mtime":"2023-02-11T10:19:36.138Z","type":"markdown"},"gitbook":{"version":"5.1.1","time":"2023-10-27T09:54:29.738Z"},"basePath":".","book":{"language":""}});
        });
    </script>
</div>

        
    <noscript>
        <style>
            .honkit-cloak {
                display: block !important;
            }
        </style>
    </noscript>
    <script>
        // Restore sidebar state as critical path for prevent layout shift
        function __init__getSidebarState(defaultValue){
            var baseKey = "";
            var key = baseKey + ":sidebar";
            try {
                var value = localStorage[key];
                if (value === undefined) {
                    return defaultValue;
                }
                var parsed = JSON.parse(value);
                return parsed == null ? defaultValue : parsed;
            } catch (e) {
                return defaultValue;
            }
        }
        function __init__restoreLastSidebarState() {
            var isMobile = window.matchMedia("(max-width: 600px)").matches;
            if (isMobile) {
                // Init last state if not mobile
                return;
            }
            var sidebarState = __init__getSidebarState(true);
            var book = document.querySelector(".book");
            // Show sidebar if it enabled
            if (sidebarState && book) {
                book.classList.add("without-animation", "with-summary");
            }
        }

        try {
            __init__restoreLastSidebarState();
        } finally {
            var book = document.querySelector(".book");
            book.classList.remove("honkit-cloak");
        }
    </script>
    <script src="gitbook/gitbook.js"></script>
    <script src="gitbook/theme.js"></script>
    
        
        <script src="gitbook/@dogatana/honkit-plugin-page-toc-button/plugin.js"></script>
        
    
        
        <script src="gitbook/@dogatana/honkit-plugin-back-to-top-button/plugin.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-copy-code-button/toggle.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-forkmegithub/plugin.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-search/search-engine.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-search/search.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
        
    

    </body>
</html>

